#include "pch.h"
#include "GMath.h"
#include "GGiEngineUtil.h"

using namespace DirectX;
GMath::Vector3::Vector3(std::initializer_list<float> data)
{
	int i = 0;
	for (auto item : data)
	{
		mData[i++] = item;
		if (i >= 3)
		{
			return;
		}
	}
}

GMath::Vector3::Vector3(float data[3])
{
	for (size_t i = 0; i < 3; i++)
	{
		mData[i] = data[i];
	}
}

float GMath::Vector3::operator[](int i) const
{
	return mData[i];
}

GMath::Vector3 GMath::Vector3::operator*(float f) const
{
	Vector3 ans;
	for (size_t i = 0; i < 3; i++)
	{
		ans[i] = mData[i] * f;
	}
	return ans;
}

GMath::Vector3 GMath::Vector3::operator/(float f) const
{
	Vector3 ans;
	for (size_t i = 0; i < 3; i++)
	{
		ans[i] = mData[i] / f;
	}
	return ans;
}

GMath::Vector3 GMath::Vector3::operator*(const Vector3& rhs) const
{
	Vector3 ans;
	for (size_t i = 0; i < 3; i++)
	{
		ans[i] = mData[i] * rhs[i];
	}
	return ans;
}

GMath::Vector3 GMath::Vector3::operator-(const Vector3& rhs) const
{
	Vector3 ans;
	for (size_t i = 0; i < 3; i++)
	{
		ans[i] = mData[i] - rhs[i];
	}
	return ans;
}

GMath::Vector3 GMath::Vector3::operator-() const
{
	return Vector3() - *this;
}

GMath::Vector3 GMath::Vector3::operator+(const Vector3& rhs) const
{
	Vector3 ans;
	for (size_t i = 0; i < 3; i++)
	{
		ans[i] = mData[i] + rhs[i];
	}
	return ans;
}

GMath::Vector3 GMath::Vector3::operator+=(const Vector3& rhs)
{
	for (size_t i = 0; i < 3; i++)
	{
		mData[i] += rhs[i];
	}
	return mData;
}

bool GMath::Vector3::operator<(const Vector3& rhs) const
{
	for (size_t i = 0; i < 3; i++)
	{
		if (mData[i] >= rhs[i])
		{
			return false;
		}
	}
	return true;
}

bool GMath::Vector3::operator>(const Vector3& rhs) const
{
	for (size_t i = 0; i < 3; i++)
	{
		if (mData[i] <= rhs[i])
		{
			return false;
		}
	}
	return true;
}

float GMath::Vector3::Length() const
{
	float d = 0;
	for (size_t i = 0; i < 3; i++)
	{
		d += mData[i] * mData[i];
	}
	d = sqrtf(d);
	return d;
}

GMath::Vector3 GMath::Vector3::Normalize()const
{
	Vector3 ans;
	
	for (size_t i = 0; i < 3; i++)
	{
		ans.mData[i] = mData[i] / Length();
	}
	return ans;
}

GMath::Vector3 GMath::Vector3::Cross(const Vector3& rhs) const
{
	/// [  i   j   k]
	///	[ v0  v1  v2]
	///	[ u0  u1  u2]
	/// = (v1 * u2 - v2 * u1)i - (v0 * u2 - v2 * u0)j + (v0 * u1 - v1 * u0)k
	Vector3 ans;
	ans[0] = mData[1] * rhs[2] - mData[2] * rhs[1];
	ans[1] = mData[2] * rhs[0] - mData[0] * rhs[2];
	ans[2] = mData[0] * rhs[1] - mData[1] * rhs[0];
	return ans;
}

float GMath::Vector3::Dot(const Vector3& rhs) const
{
	return mData[0] * rhs[0] + mData[1] * rhs[1] + mData[2] * rhs[2];
}

float& GMath::Vector3::operator[](int i)
{
	return mData[i];
};


GMath::Vector3::Vector3(const Vector4& data)
{
	for (int i = 0; i < 3; i++)
	{

		float t = data[i];
		mData[i] = t;
	}

}

GMath::Matrix GMath::Matrix::Translation(Vector3 trans)
{
	XMFLOAT4X4 temp;

	auto mat = XMMatrixTranslation(trans[0], trans[1], trans[2]);

	XMStoreFloat4x4(&temp, mat);

	return(temp);
}

GMath::Matrix GMath::Matrix::RotationPitchYawRoll(Vector3 rotation)
{
	XMFLOAT4X4 temp;

	auto mat = XMMatrixRotationRollPitchYaw(rotation[0] * GGiEngineUtil::PI / 180.0f, rotation[1] * GGiEngineUtil::PI / 180.0f, rotation[2] * GGiEngineUtil::PI / 180.0f);

	XMStoreFloat4x4(&temp, mat);

	return(temp);
}

GMath::Matrix GMath::Matrix::Scale(Vector3 scale)
{
	XMFLOAT4X4 temp;

	auto mat = XMMatrixScaling(scale[0], scale[1], scale[2]);

	XMStoreFloat4x4(&temp, mat);

	return(temp);
}

GMath::Matrix GMath::Matrix::Inverse() const
{
	auto inMat = XMMatrixInverse(nullptr, XMLoadFloat4x4(&mData));

	XMFLOAT4X4 temp;
	XMStoreFloat4x4(&temp, inMat);
	return temp;
}

GMath::Matrix GMath::Matrix::Transpose() const
{
	auto trMat = XMMatrixTranspose(XMLoadFloat4x4(&mData));

	XMFLOAT4X4 temp;
	XMStoreFloat4x4(&temp, trMat);
	return temp;
}

GMath::Vector4 GMath::Matrix::operator[](int i)
{
	return { mData.m[i][0],mData.m[i][1],mData.m[i][2],mData.m[i][3] };
}
GMath::Matrix GMath::Matrix::TRS(Vector3 Location, Vector3 Rotation, Vector3 Scale)
{
	auto t = DirectX::XMMatrixTranslation(Location[0], Location[1], Location[2]);
	auto r = DirectX::XMMatrixRotationRollPitchYaw(Rotation[0] * GGiEngineUtil::PI / 180.0f, Rotation[1] * GGiEngineUtil::PI / 180.0f, Rotation[2] * GGiEngineUtil::PI / 180.0f);
	auto s = DirectX::XMMatrixScaling(Scale[0], Scale[1], Scale[2]);
	auto worldMat = DirectX::XMMatrixMultiply(DirectX::XMMatrixMultiply(s, r), t);

	XMFLOAT4X4 temp;
	XMStoreFloat4x4(&temp, worldMat);

	return(temp);
}

GMath::Vector4::Vector4(std::initializer_list<float> data)
{
	int i = 0;
	for (auto item : data)
	{
		mData[i++] = item;
		if (i >= 4)
		{
			return;
		}
	}
}

GMath::Vector4::Vector4(const Vector3& data, float z /*= 0f */)
{
	for (int i = 0; i < 3; i++)
	{
		mData[i] = data[i];
	}
	mData[3] = z;
}

float GMath::Vector4::operator[](int i) const
{
	return mData[i];
}



GMath::Vector4 GMath::Vector4::operator*(float f) const
{
	Vector4 ans;
	for (size_t i = 0; i < 4; i++)
	{
		ans[i] = mData[i] * f;
	}
	return ans;
}

float& GMath::Vector4::operator[](int i)
{
	return mData[i];
}
GMath::Vector4 GMath::Vector4::operator*(const Matrix& mat)
{

	auto m = XMLoadFloat4x4(&mat.mData);
	auto vec = XMVectorSet(mData[0], mData[1], mData[2], mData[3]);
	vec = XMVector4Transform(vec, m);
	return Vector4(vec.m128_f32);
}
;

GMath::Vector4 GMath::Vector4::operator-(const Vector4& rhs) const
{
	Vector4 ans;
	for (size_t i = 0; i < 4; i++)
	{
		ans[i] = mData[i] - rhs[i];
	}
	return ans;
}

GMath::Vector4 GMath::Vector4::operator+(const Vector4& rhs) const
{
	Vector4 ans;
	for (size_t i = 0; i < 4; i++)
	{
		ans[i] = mData[i] + rhs[i];
	}
	return ans;
}

GMath::Vector4 GMath::Vector4::Normalize() const
{
	Vector4 ans;
	float d = 0;
	for (size_t i = 0; i < 4; i++)
	{
		d += mData[i] * mData[i];
	}
	d = sqrtf(d);
	for (size_t i = 0; i < 4; i++)
	{
		ans.mData[i] = mData[i] / d;
	}
	return ans;
}

void GMath::Vector4::operator=(const Vector3& vec3)
{
	for (int i = 0; i < 3; i++)
	{
		mData[i] = vec3[i];
	}
};

GMath::Vector2::Vector2(std::initializer_list<float> data)
{
	int i = 0;
	for (auto item : data)
	{
		mData[i++] = item;
		if (i >= 2)
		{
			return;
		}
	}
}

float GMath::Vector2::operator[](int i) const
{
	return mData[i];
}

GMath::Vector2 GMath::Vector2::operator*(float f) const
{
	Vector2 ans;
	for (size_t i = 0; i < 2; i++)
	{
		ans[i] = mData[i] * f;
	}
	return ans;
}

GMath::Vector2 GMath::Vector2::operator-(const Vector2& rhs) const
{
	Vector2 ans;
	for (size_t i = 0; i < 2; i++)
	{
		ans[i] = mData[i] - rhs[i];
	}
	return ans;
}

GMath::Vector2 GMath::Vector2::operator+(const Vector2& rhs) const
{
	Vector2 ans;
	for (size_t i = 0; i < 2; i++)
	{
		ans[i] = mData[i] + rhs[i];
	}
	return ans;
}

float& GMath::Vector2::operator[](int i)
{
	return mData[i];
}

GMath::Vector2::Vector2(float data[2])
{
	for (int i = 0; i < 2; i++)
	{
		mData[i] = data[i];
	}
}
